#pragma once

#include <queue>
#include <mutex>
#include <pthread.h>

#include "LockGuard.hpp"

const int gDefaultCap = 5;

class BlockQueue
{
public:
    BlockQueue(int capacity = gDefaultCap)
        : _capacity(capacity)
    {
        pthread_mutex_init(&lock, nullptr);
        pthread_cond_init(&_Empty, nullptr);
        pthread_cond_init(&_Full, nullptr);
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&lock);
        pthread_cond_destroy(&_Empty);
        pthread_cond_destroy(&_Full);
    }
    void push(const int &data)
    {
        lockGuard lockgrard(&lock);
        while(isQueueFull())
            pthread_cond_wait(&_Full, &lock);
        _bq.push(data);
        pthread_cond_signal(&_Empty);
    }
    void pop(int &data)
    {
        lockGuard lockguard(&lock);
        while(isQueueEmpty())
            pthread_cond_wait(&_Empty, &lock);
        data = _bq.front();
        _bq.pop();
        pthread_cond_signal(&_Full);
    }
private:
    bool isQueueEmpty()
    {
        return _bq.size() == 0;
    }
    bool isQueueFull()
    {
        return _bq.size() == _capacity;
    }
private:
    std::queue<int> _bq;
    int _capacity;
    pthread_mutex_t lock;
    pthread_cond_t _Empty;
    pthread_cond_t _Full;
};